package com.wanghua.spring.filter;

import com.wanghua.spring.filter.response.HttpCharacterResponseWrapper;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Properties;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;

/**
 * Filter 与 Listener 都属于 Servlet 的规范。
 * 内容替换 Filter。
 *      一般用于防止输出非法内容或者敏感内容。内容替换 filter 的工作原理是，在 servlet 将内容输出到 response 时，response 将内容缓存起来，在 filter
 * 中进行替换，然后再输出到客户端浏览器。由于默认的 response 并不能严格地缓存输出内容，因此需要自定义一个具备缓存功能的 response。
 *      可以通过扩展 javax.servlet.http.HttpServletResponseWrapper 类来实现自定义 response。该类实现了 java.servlet.http.HttpServletResponse 接口
 * 的所有方法，根据需要覆盖其中的相应方法即可。
 *
 */
public class OutputReplaceFilter implements Filter {
    private Properties pp = new Properties();

    public void init(FilterConfig config) throws ServletException {
        String file = config.getInitParameter("file");
        String realPath = config.getServletContext().getRealPath(file);    //敏感词配置在初始化参数中
        try {
            pp.load(new FileInputStream(realPath));
        } catch (IOException e) {
        }
    }

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpCharacterResponseWrapper response = new HttpCharacterResponseWrapper((HttpServletResponse) res);  //自定义的 response

        //如果是请求 html 静态页面， output 中是没有值的。
        chain.doFilter(req, response);  //调用下面的 filter，数据会输出到缓存中。
        String output = response.getCharArrayWriter().toString(); //获取缓存的数据。

        for (Object obj : pp.keySet()) {
            String key = (String) obj;
            output = output.replace(key, pp.getProperty(key));
        }

        PrintWriter out = res.getWriter();
        out.write(output);
        out.println("<!-- Generated at " + new java.util.Date() + " -->");
    }

    public void destroy() {
    }
}